/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved.
 * Description: HCOM 工具类
 * Author: lilianlin
 * Create: 2020-12-06
 */

#include "hcom_op_utils.h"
#include "comm.h"
#include "hcom_pub.h"
#include "hcom.h"
#include "graph/utils/node_utils.h"
#include "graph/utils/tensor_utils.h"
#include "graph/debug/ge_attr_define.h"
#include "graph/ge_local_context.h"
#include "framework/memory/memory_api.h"
#include "external/ge/ge_api_types.h" // ge对内options
#include "framework/common/ge_types.h" // ge对外options
#include "graph/utils/attr_utils.h"
#include "graph/utils/op_desc_utils.h"
#include "externalinput_pub.h"
#include "mmpa_api.h"
#include "op_hcom_comm.h"
#include "offline_build_config_parse.h"
#include "graph/ge_context.h"
#include "param_check_pub.h"
#include "config.h"
#include "coll_alg_utils.h"
#include "adapter_error_manager_pub.h"
#include "../hccl/hcom/src/hcom_private.h"

namespace hccl {
const std::string HCOM_ATTR_ROOT = "root_rank";
const std::string HCOM_ATTR_DTYPE = "dtype";
const std::string HCOM_ATTR_GROUP = "group";
const std::string HCOM_ATTR_REDUCTION = "reduction";

const std::string HCOM_ATTR_DEST_RANK = "dest_rank";
const std::string HCOM_ATTR_SR_TAG = "sr_tag";
const std::string HCOM_ATTR_SRC_RANK = "src_rank";

HcclResult HcomOpUtils::GetReduction(const ge::OpDescPtr &opDescPtr, HcclReduceOp &reduction)
{
    std::string sReduction;
    CHK_PRT_RET((!ge::AttrUtils::GetStr(opDescPtr, HCOM_ATTR_REDUCTION, sReduction)),
        HCCL_ERROR("[Get][Reduction] get attr[%s] failed.", HCOM_ATTR_REDUCTION.c_str()), HCCL_E_PARA);

    auto iter = HCOM_REDUCE_TYPE_MAP.find(sReduction);
    CHK_PRT_RET((iter == HCOM_REDUCE_TYPE_MAP.end()),
        HCCL_ERROR("[Get][Reduction] reduction[%s] is not supported, must be one of the"
        "following types: sum, prod, max, min.", sReduction.c_str()), HCCL_E_PARA);
    reduction = iter->second;
    HCCL_DEBUG("get reduction[%d] success.", reduction);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetRoot(const ge::OpDescPtr &opDescPtr, int32_t &root)
{
    CHK_PRT_RET((!ge::AttrUtils::GetInt(opDescPtr, HCOM_ATTR_ROOT, root)),
        HCCL_ERROR("[Get][Root] get attr[%s] failed.", HCOM_ATTR_ROOT.c_str()), HCCL_E_PARA);

    CHK_PRT_RET((root < 0), HCCL_ERROR("[Get][Root] root[%d] should be not less than 0.", root),
        HCCL_E_PARA);
    HCCL_DEBUG("get root[%d] success.", root);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetRankSize(const ge::OpDescPtr &opDescPtr, int32_t &rankSize)
{
    CHK_PRT_RET((!ge::AttrUtils::GetInt(opDescPtr, HCOM_ATTR_RANK_SIZE, rankSize)),
        HCCL_ERROR("[Get][RankSize] get attr[%s] failed.", HCOM_ATTR_RANK_SIZE.c_str()), HCCL_E_PARA);

    CHK_PRT_RET((rankSize <= 0), HCCL_ERROR("[Get][RankSize] rankSize[%d] should be greater than 0.", rankSize),
        HCCL_E_PARA);
    HCCL_DEBUG("get rankSize[%d] success.", rankSize);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetGroup(const ge::OpDescPtr &opDescPtr, std::string &group)
{
    if (ge::AttrUtils::HasAttr(opDescPtr, HCOM_ATTR_GROUP)) {
        if (ge::AttrUtils::GetStr(opDescPtr, HCOM_ATTR_GROUP, group) == false) {
            HCCL_ERROR("[Get][Group]errNo[0x%016llx]: get group failed. get attr \"%s\" from opDesc failed", \
                HCOM_ERROR_CODE(HCCL_E_PARA), HCOM_ATTR_GROUP.c_str());
            return HCCL_E_PARA;
        }
        CHK_PRT_RET(group.empty(), HCCL_ERROR("[Get][Group]errNo[0x%016llx] get group name failed. group"
            "from opDesc is empty.", HCOM_ERROR_CODE(HCCL_E_PARA)), HCCL_E_PARA);
    } else {
        group = HCCL_WORLD_GROUP;
    }
    HCCL_DEBUG("get group name[%s] success.", group.c_str());
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDataType(const ge::OpDescPtr &opDescPtr, HcclDataType &dataType)
{
    // 优先顺序: 'dtype' atttr > input[0]
    ge::DataType geDataType = static_cast<ge::DataType>(0);
    if (ge::AttrUtils::HasAttr(opDescPtr, HCOM_ATTR_DTYPE)) {
        if (ge::AttrUtils::GetDataType(opDescPtr, HCOM_ATTR_DTYPE, geDataType) == false) {
            HCCL_ERROR("[Get][DataType]errNo[0x%016llx]: get data type failed. get \"dtype\" from opDesc failed", \
                HCOM_ERROR_CODE(HCCL_E_PARA));
            return HCCL_E_PARA;
        }
    } else {
        CHK_SMART_PTR_NULL(opDescPtr->GetInputDescPtr(0));
        // 指针指向的各个算子的DataType一致，获取第一个op的即可
        geDataType = opDescPtr->GetInputDescPtr(0)->GetDataType();
    }
    CHK_RET(TransformDataType(geDataType, dataType));
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDataType(const ge::OpDescPtr &opDescPtr, std::string &dataType)
{
    HcclDataType hcclDataType;
    HcclResult ret = GetDataType(opDescPtr, hcclDataType);
    CHK_PRT_RET(ret != HCCL_SUCCESS,
        HCCL_ERROR("[Get][DataType]op[%s]: get data type failed.", opDescPtr->GetName().c_str()), HCCL_E_PARA);
    auto iter = HCOM_DATA_TYPE_STR_MAP.find(hcclDataType);
    CHK_PRT_RET((iter == HCOM_DATA_TYPE_STR_MAP.end()), \
        HCCL_ERROR("[Get][Data]node[%s]: hccl data type[%s] transform failed.", opDescPtr->GetName().c_str(), \
            GetDataTypeEnumStr(hcclDataType).c_str()), HCCL_E_INTERNAL);
    dataType = iter->second;
    HCCL_DEBUG("get data type[%s] success.", dataType.c_str());
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::TransformDataType(const ge::DataType geDataType, HcclDataType &hcclDataType)
{
    auto iter = HCOM_DATA_TYPE_MAP.find(geDataType);
    CHK_PRT_RET((iter == HCOM_DATA_TYPE_MAP.end()),
        HCCL_ERROR("[Trans][DataType]errNo[0x%016llx] GeDataType[%lld] is not supported, must be one of the"
        "following types: int8, uint8, int16, uint16, int32, uint32, int64, uint64, float16, float32, "\
        "float64, bfloat16.", HCOM_ERROR_CODE(HCCL_E_PARA), geDataType), HCCL_E_PARA);
    hcclDataType = iter->second;
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAllInputsTensorMemSize(const ge::OpDescPtr &opDescPtr, uint64_t &tensorSize)
{
    tensorSize = 0;
    for (uint32_t i = 0; i < opDescPtr->GetAllInputsSize(); i++) {
        auto inTensor = opDescPtr->GetInputDesc(i);
        uint64_t memSize = 0;
        HcclResult ret = GetTensorMemSize(inTensor, memSize);
        CHK_PRT_RET(ret != HCCL_SUCCESS,
            HCCL_ERROR("[Get][AllInputsTensorMemSize]node[%s] input[%u] GetTensorMemSize failed.",
            opDescPtr->GetName().c_str(), i), ret);
        tensorSize += memSize;
        HCCL_DEBUG("node[%s] has %u inputs, input[%u] size %llu bytes.", opDescPtr->GetName().c_str(),
            opDescPtr->GetAllInputsSize(), i, tensorSize);
    }
    HCCL_DEBUG("node[%s] has %u inputs, total size %llu bytes.", opDescPtr->GetName().c_str(),
        opDescPtr->GetAllInputsSize(), tensorSize);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAllOutputsTensorMemSize(const ge::OpDescPtr &opDescPtr, uint64_t &tensorSize)
{
    tensorSize = 0;
    for (uint32_t i = 0; i < opDescPtr->GetOutputsSize(); i++) {
        auto inTensor = opDescPtr->GetOutputDesc(i);
        uint64_t memSize = 0;
        HcclResult ret = GetTensorMemSize(inTensor, memSize);
        CHK_PRT_RET(ret != HCCL_SUCCESS,
            HCCL_ERROR("[Get][AllOutputsTensorMemSize]node[%s] output[%u] GetTensorMemSize failed.",
            opDescPtr->GetName().c_str(), i), ret);
        tensorSize += memSize;
    }
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetTensorMemSize(const ge::GeTensorDesc &tensorDesc, uint64_t &memSize)
{
    const u32 memoryAlignRatio = 2; // GE要求内存需要32B对齐后，再外加32B. out = (in + 2 * 32 - 1) / 32 * 32
    const u32 memoryAlignSize = 32; // GE要求内存需要32B对齐后，再外加32B. out = (in + 2 * 32 - 1) / 32 * 32
    auto shape = tensorDesc.GetShape();
    auto format = tensorDesc.GetFormat();
    auto dataType = tensorDesc.GetDataType();
    int64_t size = 0;
    bool bErr = (ge::GRAPH_SUCCESS != ge::TensorUtils::CalcTensorMemSize(shape, format, dataType, size));
    CHK_PRT_RET((bErr) || (size < 0), HCCL_ERROR("[Get][TensorMemSize]In GetTensorMemSize, CalcTensorMemSize"
        "failed, Format[%d], dataType[%d], size[%lld]", format, dataType, size), HCCL_E_PARA);
    memSize = ((size + memoryAlignRatio * memoryAlignSize - 1) / memoryAlignSize) * memoryAlignSize;
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAllInputsTensorOriginSize(const ge::OpDescPtr &opDescPtr, uint64_t &tensorSize)
{
    tensorSize = 0;
    for (uint32_t i = 0; i < opDescPtr->GetAllInputsSize(); i++) {
        auto inTensor = opDescPtr->GetInputDesc(i);
        uint64_t size = 0;
        HcclResult ret = GetTensorOriginSize(inTensor, size);
        CHK_PRT_RET(ret != HCCL_SUCCESS,
            HCCL_ERROR("[Get][AllInputsTensorOriginSize]node[%s] input[%u] GetTensorOriginSize failed.",
            opDescPtr->GetName().c_str(), i), ret);
        HCCL_DEBUG("node[%s] has %u inputs, input[%u] size %llu bytes.", opDescPtr->GetName().c_str(),
            opDescPtr->GetAllInputsSize(), i, size);
        tensorSize += size;
    }
    HCCL_DEBUG("node[%s] has %u inputs, total size %llu bytes.", opDescPtr->GetName().c_str(),
        opDescPtr->GetAllInputsSize(), tensorSize);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetTensorOriginSize(const ge::GeTensorDesc &tensorDesc, uint64_t &size)
{
    HcclDataType hcclDataType;
    auto geDataType = tensorDesc.GetDataType();
    CHK_RET(TransformDataType(geDataType, hcclDataType));
    uint32_t dataTypeSize;
    CHK_RET(SalGetDataTypeSize(hcclDataType, dataTypeSize));
    uint64_t shapeSize = static_cast<uint64_t>(tensorDesc.GetOriginShape().GetShapeSize());

    CHK_PRT_RET((shapeSize > INVALID_U64 / dataTypeSize), HCCL_ERROR("[Get][TensorOriginSize]shape size[%llu]"
        "is overflow.", shapeSize), HCCL_E_PARA);
    size = shapeSize * dataTypeSize;

    return HCCL_SUCCESS;
}
#ifndef HCOM_EXECUTOR
HcclResult HcomOpUtils::CreateFusionConfigVersion(std::string &configVersion)
{
    uint32_t ret = 0;
    fe::PlatformInfoManager &configInst = fe::PlatformInfoManager::Instance();
    fe::PlatformInfo autoPlatInfo;
    fe::OptionalInfo autoOptinalInfo;
    ret = configInst.GetPlatformInfoWithOutSocVersion(autoPlatInfo, autoOptinalInfo);
    if (ret == 0) {
        configVersion = autoOptinalInfo.soc_version;
        HCCL_INFO("get soc version success, [%s], return [%u]", configVersion.c_str(), ret);
    } else {
        HCCL_ERROR("[Hcom][Optimizer]get soc version failed.");
    }
    return HCCL_SUCCESS;
}
#endif
HcclResult HcomOpUtils::GetPathFromEnv(const char* environment, std::string &fusionPath)
{
    std::string libPath;
    char* getTunePath = getenv(environment);
    if (getTunePath != nullptr) {
        libPath = getTunePath;
        fusionPath = libPath + "/";
        HCCL_INFO("Get Path from Env success.");
    } else {
        return HCCL_E_AGAIN;
    }
    return HCCL_SUCCESS;
}
#ifndef HCOM_EXECUTOR
HcclResult HcomOpUtils::GetFileNameFromPath(std::string &Path, std::string &fusionFile)
{
    std::string fileName;
    std::string ConfigVersion;
    char getDefaultPath[PATH_MAX];
    if (realpath(Path.c_str(), getDefaultPath) == nullptr) {
        HCCL_WARNING("[Get][FusionConfigRealPath]path %s is not a valid path", Path.c_str());
        return HCCL_E_AGAIN;
    }

    CHK_RET(HcomOpUtils::CreateFusionConfigVersion(ConfigVersion));
    fileName = ConfigVersion + "_gradient_fusion.json";
    fusionFile = Path + fileName;
    return HCCL_SUCCESS;
}
#endif

bool HcomOpUtils::HcomOpIsSupportedBool(const std::string &opType)
{
    const std::vector<std::string> hcomOpSupportBoolMap = {
        HCCL_KERNEL_OP_TYPE_BROADCAST,
        HCCL_KERNEL_OP_TYPE_ALLGATHER,
        HCCL_KERNEL_OP_TYPE_SEND,
        HCCL_KERNEL_OP_TYPE_RECEIVE,
        HCCL_KERNEL_OP_TYPE_ALLTOALLV,
        HCCL_KERNEL_OP_TYPE_ALLTOALLVC,
        HCCL_KERNEL_OP_TYPE_GATHER_ALLTOALLV,
        HCCL_KERNEL_OP_TYPE_ALLTOALL
    };
    std::vector<std::string>::const_iterator it = std::find(hcomOpSupportBoolMap.begin(),
        hcomOpSupportBoolMap.end(), opType);
    return (it != hcomOpSupportBoolMap.end()) ? true : false;
}

HcclResult HcomOpUtils::ConversionOpDataType(const ge::OpDescPtr &op, const std::string &opType,
    HcclDataType &dataType)
{
    // 获取GE数据类型
    ge::DataType geDataType = static_cast<ge::DataType>(0);
    if (ge::AttrUtils::HasAttr(op, HCOM_ATTR_DTYPE)) {
        if (ge::AttrUtils::GetDataType(op, HCOM_ATTR_DTYPE, geDataType) == false) {
            HCCL_ERROR("[Get][DataType]errNo[0x%016llx]: get data type failed. get \"dtype\" from opDesc failed", \
                HCOM_ERROR_CODE(HCCL_E_PARA));
            return HCCL_E_PARA;
        }
    } else {
        CHK_SMART_PTR_NULL(op->GetInputDescPtr(0));
        // 指针指向的各个算子的DataType一致，获取第一个op的即可
        geDataType = op->GetInputDescPtr(0)->GetDataType();
    }

    // 判断当前算子是否支持BOOL类型 且数据类型是否是BOOL,将GE的BOOL类型转换成HCCL的INT8
    if (HcomOpIsSupportedBool(opType) && (geDataType == ge::DT_BOOL)) {
        dataType = HCCL_DATA_TYPE_INT8;
    } else {
        auto iter = HCOM_DATA_TYPE_MAP.find(geDataType);
        CHK_PRT_RET((iter == HCOM_DATA_TYPE_MAP.end()), \
            HCCL_ERROR("[Get][DataType]errNo[0x%016llx] node[%s]: data type[%lld] is not supported, must be "\
                "one of the following types: "\
                "int8, uint8, int16, uint16, int32, uint32, int64, uint64, float16, float32, float32, "\
                "float64.", HCOM_ERROR_CODE(HCCL_E_PARA), op->GetName().c_str(), \
                geDataType), HCCL_E_PARA);
        dataType = iter->second;
    }
    HCCL_INFO("[hcom][ConversionOpDataType]conversion opType[%s] geDataType[%lld] to data type[%s] success.",\
        opType.c_str(), geDataType, GetDataTypeEnumStr(dataType).c_str());
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAlltoAllvcStagedScratchMemSize(ge::Node& node, const int64_t &hcomComm,
    const string &sGroup, u32 rankSize, u64 &getMemSize)
{
    if (rankSize > ALLTOALLVC_RANK_MAX_NUM) {
        HCCL_ERROR("[GetAlltoAllvcStagedScratchMemSize] Invalid rankSize[%u]", rankSize);
        return HCCL_E_PARA;
    }
    u64 memSize = 0;
    HcclDataType sendType;
    HcclDataType recvType;
    CHK_RET(GetAlltoAllDataType(node.GetOpDesc(), sendType, recvType));

    std::vector<int64_t> sendCountMatrix;
    auto op = node.GetOpDesc();
    if (ge::AttrUtils::HasAttr(op, "send_count_matrix")) {
        CHK_RET(GetAlltoAllCountMatrix(op, sendCountMatrix));
    } else {
        CHK_RET(GetAlltoAllCountMatrix(node, sendCountMatrix));
    }
    if (sendCountMatrix.size() < rankSize * rankSize) {
        HCCL_ERROR("[sendCountMatrix] size[%u] is invalid, expect size: %llu",
            sendCountMatrix.size(), rankSize * rankSize);
        return HCCL_E_PARA;
    }

    u32 rankID = 0;
    CHK_RET(GetRankId(hcomComm, sGroup, rankID));
    u32 sendTypeSize = 0, recvTypeSize = 0;
    CHK_RET(SalGetDataTypeSize(sendType, sendTypeSize));
    CHK_RET(SalGetDataTypeSize(recvType, recvTypeSize));
    std::vector<SendRecvInfo> allMeshAggregationSendRecvInfo;
    for (u32 i = 0; i < rankSize; i++) {
        SendRecvInfo sendRecvInfo;
        u64 curSendDispls = 0;
        u64 curRecvDispls = 0;
        for (u32 j = 0; j < rankSize; j++) {
            u64 curSendCounts = sendCountMatrix[i * rankSize + j];
            sendRecvInfo.sendCounts.push_back(curSendCounts);
            sendRecvInfo.sendDispls.push_back(curSendDispls);
            sendRecvInfo.sendLength.push_back(curSendCounts * sendTypeSize);
            sendRecvInfo.sendOffset.push_back(curSendDispls * sendTypeSize);
            HCCL_DEBUG("GetAlltoAllvcStagedScratchMemSize rankID[%u], curSendCounts[%llu], curSendDispls[%llu]",
                i, curSendCounts, curSendDispls);
            curSendDispls += curSendCounts;

            u64 curRecvCounts = sendCountMatrix[i + rankSize * j];
            sendRecvInfo.recvCounts.push_back(curRecvCounts);
            sendRecvInfo.recvDispls.push_back(curRecvDispls);
            sendRecvInfo.recvLength.push_back(curRecvCounts * recvTypeSize);
            sendRecvInfo.recvOffset.push_back(curRecvDispls * recvTypeSize);
            HCCL_DEBUG("GetAlltoAllvcStagedScratchMemSize rankID[%u], curRecvCounts[%llu], curRecvDispls[%llu]",
                i, curRecvCounts, curRecvDispls);
            curRecvDispls += curRecvCounts;
        }
        allMeshAggregationSendRecvInfo.push_back(std::move(sendRecvInfo));
    }

    CHK_RET(HcomGetAlltoAllvcStagedWorkSpaceMemSize(sGroup.c_str(), allMeshAggregationSendRecvInfo, memSize));
    getMemSize += memSize;

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAlltoAllCountMatrix(const ge::OpDescPtr &op, std::vector<int64_t> &sendCountMatrix)
{
    CHK_PRT_RET((!ge::AttrUtils::GetListInt(op, "send_count_matrix", sendCountMatrix)),
        HCCL_ERROR("[Set][AlltoAllVParams]op[%s] get attr[%s] failed.",
        HCCL_KERNEL_OP_TYPE_ALLTOALLV.c_str(), "send_count_matrix"), HCCL_E_PARA);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAlltoAllCountMatrix(ge::Node& node, std::vector<int64_t> &sendCountMatrix)
{
    // 1、判断是否是const 节点 NodeUtils::IsConst(*really_parent_node)) 是走老流程，不是判断是否是data节点，是去获取对应输入父节点，不是
    auto op = ge::OpDescUtils::CreateOperatorFromNode(node.shared_from_this());
    auto sendCountMatrixTensor = ge::OpDescUtils::GetInputConstData(op, 1);
    if (sendCountMatrixTensor == nullptr) {
        CHK_RET(GetConstInputAcrossGraph(sendCountMatrixTensor, 1U, node));
    }

    CHK_RET(GetVectorFromTensor(sendCountMatrixTensor, sendCountMatrix));

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAlltoAllDataType(const ge::OpDescPtr &op,
    HcclDataType& sendType, HcclDataType& recvType)
{
    auto opDescPtr = op->GetInputDescPtr(0);
    ge::DataType graphSendType = opDescPtr == nullptr ? ge::DT_INT8 : opDescPtr->GetDataType(); // 如果不发送则填int8类型
    auto iter = HCOM_DATA_TYPE_MAP.find(graphSendType);
    CHK_PRT_RET((iter == HCOM_DATA_TYPE_MAP.end()), \
        HCCL_ERROR("[Get][DataType]errNo[0x%016llx] node[%s]: data type[%lld] is not supported, must be"
            "one of the following types: "\
            "int8, uint8, int16, uint16, int32, uint32, int64, uint64, float16, float32, float32, "\
            "float64.", HCOM_ERROR_CODE(HCCL_E_PARA), op->GetName().c_str(), \
            graphSendType), HCCL_E_PARA);
    sendType = iter->second;

    opDescPtr = op->GetOutputDescPtr(0);
    ge::DataType graphRecvType = opDescPtr == nullptr ? ge::DT_INT8 : opDescPtr->GetDataType(); // 如果不接收则填int8类型
    iter = HCOM_DATA_TYPE_MAP.find(graphRecvType);
    CHK_PRT_RET((iter == HCOM_DATA_TYPE_MAP.end()), \
        HCCL_ERROR("[Get][DataType]errNo[0x%016llx] node[%s]: data type[%lld] is not supported, must be"
            "one of the following types: "\
            "int8, uint8, int16, uint16, int32, uint32, int64, uint64, float16, float32, float32, "\
            "float64.", HCOM_ERROR_CODE(HCCL_E_PARA), op->GetName().c_str(), \
            graphRecvType), HCCL_E_PARA);
    recvType = iter->second;

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetConstInputAcrossGraph(const ge::GeTensor* &tensor, u32 index, ge::Node& node)
{
    ge::NodePtr really_parent_node = nullptr;
    if ((ge::NodeUtils::GetInNodeCrossPartionedCallNode(node.shared_from_this(),
        index, really_parent_node) == ge::GRAPH_SUCCESS) &&
        (really_parent_node != nullptr) && (ge::NodeUtils::IsConst(*really_parent_node))) {
        std::vector<ge::GeTensorPtr> weight = ge::OpDescUtils::MutableWeights(really_parent_node);
        if (weight.size() != 0) {
            CHK_PTR_NULL(weight[0].get());
            tensor = weight[0].get();
        }
    } else {
        HCCL_ERROR("GetConstInputAcrossGraph failed");
        return HCCL_E_NOT_FOUND;
    }
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetVectorFromTensor(const ge::GeTensor* tensor, std::vector<int64_t>& vector)
{
    auto buff = tensor->GetData().GetData();
    const auto len = tensor->GetData().GetSize();
    auto buffTmp = const_cast<int64_t*>(reinterpret_cast<const int64_t*>(buff));
    for (size_t i = 0UL; i < (len / sizeof(int64_t)); ++i) {
        vector.emplace_back(buffTmp[i]);
    }

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetRankId(const int64_t &hcomComm, const string &sGroup, u32 &rankId)
{
    if (hcomComm == static_cast<int64_t>(CommNumHcom::COMM_VALUE_DEFAULT)) {
        CHK_RET(GetHcclRankId(sGroup.c_str(), &rankId));
    } else {
        CHK_RET(HcclCommGraphGetRankId(hcomComm, &rankId));
    }
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDestRank(const ge::OpDescPtr &opDescPtr, int32_t &destRank)
{
    CHK_PRT_RET((!ge::AttrUtils::GetInt(opDescPtr, HCOM_ATTR_DEST_RANK, destRank)),
                HCCL_ERROR("[Get][RankSize] get attr[%s] failed.", HCOM_ATTR_DEST_RANK.c_str()), HCCL_E_PARA);

    CHK_PRT_RET((destRank < 0), HCCL_ERROR("[Get][destRank] destRank[%d] should not be negative.", destRank),
                HCCL_E_PARA);
    HCCL_DEBUG("get destRank[%d] success.", destRank);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetSrTag(const ge::OpDescPtr &opDescPtr, int32_t &srTag)
{
    CHK_PRT_RET((!ge::AttrUtils::GetInt(opDescPtr, HCOM_ATTR_SR_TAG, srTag)),
                HCCL_ERROR("[Get][RankSize] get attr[%s] failed.", HCOM_ATTR_SR_TAG.c_str()), HCCL_E_PARA);

    CHK_PRT_RET((srTag < 0), HCCL_ERROR("[Get][srTag] srTag[%d] should not be negative.", srTag),
                HCCL_E_PARA);
    HCCL_DEBUG("get srTag[%d] success.", srTag);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetSrcRank(const ge::OpDescPtr &opDescPtr, int32_t &srcRank)
{
    CHK_PRT_RET((!ge::AttrUtils::GetInt(opDescPtr, HCOM_ATTR_SRC_RANK, srcRank)),
                HCCL_ERROR("[Get][RankSize] get attr[%s] failed.", HCOM_ATTR_SRC_RANK.c_str()), HCCL_E_PARA);

    CHK_PRT_RET((srcRank < 0), HCCL_ERROR("[Get][destRank] destRank[%d] should not be negative.", srcRank),
                HCCL_E_PARA);
    HCCL_DEBUG("get srcRank[%d] success.", srcRank);

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDevId(const int64_t &hcomComm, const string &sGroup, s32 &devId)
{
    if (hcomComm == static_cast<int64_t>(CommNumHcom::COMM_VALUE_DEFAULT)) {
        CHK_RET(HcomGetDevId(sGroup.c_str(), &devId));
    } else {
        CHK_RET(HcclCommGraphGetDevId(hcomComm, &devId));
    }
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::CheckAlltoAllvcRank(const ge::Node &node, const int64_t &hcomComm,
    const string &sGroup)
{
    u32 rankId = 0;
    CHK_RET(GetRankId(hcomComm, sGroup, rankId));

    u32 alltoallvcRank = 0;
    bool bRet = ge::AttrUtils::GetInt(node.GetOpDesc(), "rank", alltoallvcRank);
    CHK_PRT_RET(!bRet, HCCL_ERROR("errNo[0x%016llx] get alltoallvc rank failed. no \"rank\" in opDesc", \
        HCOM_ERROR_CODE(HCCL_E_PARA)), HCCL_E_PARA);

    RPT_INPUT_ERR(rankId != alltoallvcRank, "EI0003",
        std::vector<std::string>({"ccl_op", "parameter", "value", "tips"}),\
        std::vector<std::string>({"CheckAlltoAllvcRank", "rankId", std::to_string(rankId), "please check rankId"}));

    CHK_PRT_RET(rankId != alltoallvcRank, HCCL_ERROR("errNo[0x%016llx] alltoallvc rank is invalid. " \
        "rank value %u, expect %u", HCOM_ERROR_CODE(HCCL_E_PARA), alltoallvcRank, rankId), HCCL_E_PARA);
    return HCCL_SUCCESS;
}

bool HcomOpUtils::IsNeedCalTaskNum(const std::string &sCollectiveType)
{
    const std::vector<std::string> hcomNeedCalTaskNumMap = {
        HCCL_KERNEL_OP_TYPE_ALLREDUCE,
        HCCL_KERNEL_OP_TYPE_ALLGATHER,
        HCCL_KERNEL_OP_TYPE_REDUCESCATTER,
        HCCL_KERNEL_OP_TYPE_ALLTOALL,
        HCCL_KERNEL_OP_TYPE_ALLTOALLV,
        HCCL_KERNEL_OP_TYPE_ALLTOALLVC
    };
    auto it = std::find(hcomNeedCalTaskNumMap.begin(), hcomNeedCalTaskNumMap.end(), sCollectiveType);
    return (it != hcomNeedCalTaskNumMap.end()) ? true : false;
}

HcclResult HcomOpUtils::GetDfxTaskNum(const std::string &sCollectiveType, u32 &taskNum)
{
    if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLREDUCE) {
        taskNum += DFX_PADDING_TASK_NUM;
    }
    taskNum += DFX_DEFAULT_TASK_NUM;
    HCCL_DEBUG("[GetDfxTaskNum] cur task num[%u].", taskNum);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetToSlaveStreamTaskNum(const std::string &sCollectiveType,
    u64 streamNum, u64 piplineSliceNum, u32 &taskNum)
{
    u32 taskNumTmp = 0;
    if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLREDUCE) {
        taskNumTmp = streamNum * MASTER_STREAM_EVENT_NUM * COM_STEP_NUM;
    } else {
        taskNumTmp = streamNum * MASTER_STREAM_EVENT_NUM;
    }
    if (piplineSliceNum >= MIN_PIPLINE_SLICE_NUM) {
        taskNumTmp += piplineSliceNum * PIPLINE_STREAM_EVENT_NUM * COM_STEP_NUM;
    }
    taskNum += taskNumTmp;
    HCCL_DEBUG("[GetToSlaveStreamTaskNum] cur task num[%u].", taskNum);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetToMasterStreamTaskNum(const std::string &sCollectiveType, u32 &taskNum)
{
    if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLREDUCE) {
        taskNum += (SLAVE_STREAM_EVENT_NUM * COM_STEP_NUM);
    } else {
        taskNum += SLAVE_STREAM_EVENT_NUM;
    }
    HCCL_DEBUG("[GetToMasterStreamTaskNum] cur task num[%u].", taskNum);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDefaultAlgoLevel0Module(s32 deviceNumPerServer, AlgTypeLevel0 &algType)
{
    std::string soc_version;
    if (ge::GetThreadLocalContext().GetOption(ge::SOC_VERSION, soc_version) != ge::GRAPH_SUCCESS) {
        HCCL_WARNING("[GetDefaultAlgoLevel0Module]Didn't find soc version");
    }
    if (soc_version == "Ascend910B") {
        algType = AlgTypeLevel0::ALG_LEVEL0_8P_RING;
    } else if (deviceNumPerServer == TASK_NUM_DEVICE_FOUR) {
        algType = AlgTypeLevel0::ALG_LEVEL0_4P_MESH;
    } else {
        algType = AlgTypeLevel0::ALG_LEVEL0_NP_SINGLE_RING;
    }
    auto iter = HCCL_ALGO_LEVEL0_NAME_MAP.find(algType);
    CHK_PRT_RET(iter == HCCL_ALGO_LEVEL0_NAME_MAP.end(), HCCL_ERROR("level0: algType[%u] is invalid.", algType),
        HCCL_E_INTERNAL);
    HCCL_DEBUG("hccl algorithm: [Module(aiserver)] there are %d device in level0, using %s algo.", \
        deviceNumPerServer, iter->second.c_str());
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDefaultAlgoLevel1(s32 serverNum, AlgTypeLevel1 &algType)
{
    u32 num = serverNum;
    if (num >=  HCCL_INTER_SERVER_RING_ALGO_MAX_SUPPORT_SERVER_NUM) {
        // server 数为 8 以上：使用 HD 算法
        algType = AlgTypeLevel1::ALG_LEVEL1_HD;
    } else {
        // server 数为 2 的非整数次幂：使用 RING 算法
        // server 数为 2 的整数次幂：使用 HD 算法
        algType = (((num & (num - 1)) != 0) || (num == 1)) ? \
            AlgTypeLevel1::ALG_LEVEL1_RING : AlgTypeLevel1::ALG_LEVEL1_HD;
    }

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::SplitHcclOpType(const std::string &algoConfig, const std::string &opType,
    std::string &specificAlgoConfig)
{
    // 对algoConfig进行/切分
    std::size_t foundSeparator = algoConfig.find("/");
    if ((foundSeparator == algoConfig.length() - 1) || (foundSeparator == 0)) {
        HCCL_ERROR("[HcomOpUtils][SplitHcclOpType]algo config is invalid at split sign.");
        return HCCL_E_PARA;
    } else if (foundSeparator == std::string::npos) {
        specificAlgoConfig = algoConfig;
        return HCCL_SUCCESS;
    }

    std::string remainAlgoConfig = algoConfig.substr(foundSeparator + 1);
    std::string currentConfig = algoConfig.substr(0, foundSeparator);
    std::size_t foundEqual = currentConfig.find("=");
    if ((foundEqual == algoConfig.length() - 1) || (foundEqual == 0) || (foundEqual == std::string::npos)) {
        HCCL_ERROR("[HcomOpUtils][SplitHcclOpType]algo config is invalid at equal sign.");
        return HCCL_E_PARA;
    }

    std::string currentOpType = currentConfig.substr(0, foundEqual);
    if (currentOpType == opType) {
        specificAlgoConfig = currentConfig;
        return HCCL_SUCCESS;
    }

    if (!remainAlgoConfig.empty()) {
        CHK_RET(SplitHcclOpType(remainAlgoConfig, opType, specificAlgoConfig));
    }
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAlgoLevel1(s32 serverNum, std::string &opType, AlgTypeLevel1 &algType)
{
    std::string hcclAlgo = SalGetEnv("HCCL_ALGO");
    if (hcclAlgo != "EmptyString") {
        // 删除空格
        std::string rawAlgoConfig = hcclAlgo;
        rawAlgoConfig.erase(std::remove(rawAlgoConfig.begin(), rawAlgoConfig.end(), ' '), rawAlgoConfig.end());

        std::string algoConfig;
        CHK_RET(SplitHcclOpType(rawAlgoConfig, opType, algoConfig));

        // 匹配字段"level1:"
        std::string level1 = "level1:";
        std::size_t found = algoConfig.find(level1);
        if ((found == 0) || (found == (algoConfig.length() - level1.size())) || found == std::string::npos) {
            // HCCL_ALGO中"level1:"配置有问题，走默认获取AlgoLevel1方式
            HCCL_WARNING("Level 1 is not configured.");
            CHK_RET(GetDefaultAlgoLevel1(serverNum, algType));
        } else {
            // 截取HCCL_ALGO中"level1:"之后的字段
            std::string remainAlgoConfig = algoConfig.substr(found + level1.size());
            std::string level1AlgoConfig = remainAlgoConfig.substr(0, remainAlgoConfig.find(";"));

            const std::map<std::string, AlgTypeLevel1> hcclAlgoLevel1Map = {
                {"null", AlgTypeLevel1::ALG_LEVEL1_RESERVED},
                {"ring", AlgTypeLevel1::ALG_LEVEL1_WHOLE_RING},
                {"pipeline", AlgTypeLevel1::ALG_LEVEL1_PIPELINE},
                {"fullmesh", AlgTypeLevel1::ALG_LEVEL1_RESERVED},
                {"H-D_R", AlgTypeLevel1::ALG_LEVEL1_HD},
                {"pairwise", AlgTypeLevel1::ALG_LEVEL1_RESERVED},
                {"NHR", AlgTypeLevel1::ALG_LEVEL1_NHR},
                {"NHR_V1", AlgTypeLevel1::ALG_LEVEL1_NHR_V1},
                {"AHC", AlgTypeLevel1::ALG_LEVEL1_AHC},
                {"AHC_BROKE", AlgTypeLevel1::ALG_LEVEL1_AHC_BROKE},
                {"NB", AlgTypeLevel1::ALG_LEVEL1_NB},
                {"NA", AlgTypeLevel1::ALG_LEVEL1_RESERVED},
            };

            auto iterAlgoLevel1 = hcclAlgoLevel1Map.find(level1AlgoConfig);
            if (iterAlgoLevel1 == hcclAlgoLevel1Map.end()) {
                HCCL_ERROR("[GetAlgoLevel1] algo config is invalid, level %s is not supported.",
                    level1AlgoConfig.c_str());
                return HCCL_E_PARA;
            }

            algType = iterAlgoLevel1->second;
            if (algType == AlgTypeLevel1::ALG_LEVEL1_RESERVED) {
                CHK_RET(GetDefaultAlgoLevel1(serverNum, algType));
            }
        }
    } else {
        CHK_RET(GetDefaultAlgoLevel1(serverNum, algType));
    }

    HCCL_INFO("[GetAlgoLevel1] level1[%u].", algType);
    auto iter = HCCL_ALGO_LEVEL1_NAME_MAP.find(algType);
    CHK_PRT_RET(iter == HCCL_ALGO_LEVEL1_NAME_MAP.end(), HCCL_ERROR("level1: algType[%u] is invalid.", algType),
        HCCL_E_INTERNAL);
    HCCL_DEBUG("hccl algorithm: there are %d server in level1,"\
        " the algorithm for setting environment variables is %s algo.", serverNum, iter->second.c_str());
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAlgType(const ge::Node &node, s32 deviceNumPerServer,
    s32 serverNum, std::string opType, AlgType &algType)
{
    AlgTypeLevel0 algType0;
    AlgTypeLevel1 algType1;

    // 因为非标卡计算出来的task num比标卡场景多，因此task num精确评估暂不区分标卡和非标卡
    CHK_RET(GetDefaultAlgoLevel0Module(deviceNumPerServer, algType0));
    CHK_RET(GetAlgoLevel1(serverNum, opType, algType1));
    algType.algoLevel0 = algType0;
    algType.algoLevel1 = algType1;
    HCCL_INFO("average device count [%d], algorithm type [%u] is selected.", deviceNumPerServer, algType.algoLevel0);
    return HCCL_SUCCESS;
}

// module表示通信域Inner中的节点, moduleNum即Inner中的节点个数。
// 910B A+K: module等效于server  910B A+X:一个server包含两个module
HcclResult HcomOpUtils::GetModuleInfo(const std::vector<RankInfo_t> &rankList, bool &multiModuleDiffDeviceNumMode)
{
    multiModuleDiffDeviceNumMode = false;

    DevType devType;
    CHK_RET(GetOffDeviceTypeWithoutDev(devType));
    HCCL_INFO("[HcomOpUtils][GetModuleInfo] devType[%d], rankList.size[%u]", devType, rankList.size());
    if (devType != DevType::DEV_TYPE_910B || rankList.size() == 0) {
        return HCCL_SUCCESS;
    }

    std::map<u32, std::vector<RankInfo_t>> moduleMap;
    for (RankInfo_t rankInfo : rankList) {
        if (static_cast<s32>(rankInfo.deviceInfo.devicePhyId) == HOST_DEVICE_ID) {
            continue;
        }
        u32 moduleIdx = rankInfo.serverIdx * FACTOR_NUM_TWO + rankInfo.deviceInfo.devicePhyId / DEVICE_PER_MODULE;
        auto iter = moduleMap.find(moduleIdx);
        if (iter == moduleMap.end()) {
            std::vector<RankInfo_t> rankInfoList;
            rankInfoList.push_back(rankInfo);
            moduleMap.insert(std::make_pair(moduleIdx, rankInfoList));
        } else {
            iter->second.push_back(rankInfo);
        }
    }

    // 无NPU参与通信
    if (moduleMap.size() == 0) {
        return HCCL_SUCCESS;
    }
    u32 preDeviceNum = moduleMap.begin()->second.size();
    u32 curDeviceNum = preDeviceNum;
    for (auto moduleInfo: moduleMap) {
        curDeviceNum = moduleInfo.second.size();
        HCCL_DEBUG("[HcomOpUtils][GetModuleInfo] module[%d] contains [%d]devices", moduleInfo.first, curDeviceNum);
        for (auto rankInfo : moduleInfo.second) {
            HCCL_DEBUG("[HcomOpUtils][GetModuleInfo] moduleIdx[%d] Info: rankId[%d], serverId[%s], serverIdx[%d], "
                "devicePhyId[%d]", moduleInfo.first, rankInfo.rankId, rankInfo.serverId.c_str(), rankInfo.serverIdx,
                rankInfo.deviceInfo.devicePhyId);
        }
        if (curDeviceNum != preDeviceNum) {
            multiModuleDiffDeviceNumMode = true;
            HCCL_INFO("[HcomOpUtils][GetModuleInfo] different module contains different numbers of cards:[%d]",
                multiModuleDiffDeviceNumMode);
            return HCCL_SUCCESS;
        }
    }
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDevAndSerNumFromRankTable(s32 &deviceNumPerServer, s32 &serverNum,
    bool &multiModuleDiffDeviceNumMode)
{
    HcclResult ret = HCCL_SUCCESS;
    string ranktableFile;
    if (ge::GetThreadLocalContext().GetOption(ge::OPTION_EXEC_RANK_TABLE_FILE, ranktableFile) ==
            ge::GRAPH_SUCCESS) {
        HcomInfo hcomInfo;
        std::string rankTableM;
        std::string realFilePath;
        std::string identify = "0";
        u32 rankTableSize = 0;
        DevType devType = DevType::DEV_TYPE_910;
        HCCL_INFO("get ranktable is [%s].", ranktableFile.c_str());
        ret = HcomLoadRanktableFile(ranktableFile.c_str(), rankTableM, realFilePath);
        CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[GetDevAndSerNumFromRankTable]errNo[0x%016llx] rankTablePath[%s]"
            "load rankTable error.", HCCL_ERROR_CODE(HCCL_E_INTERNAL), ranktableFile.c_str()), HCCL_E_INTERNAL);
        ret = HcomCheckRankTable(rankTableM.c_str(), rankTableSize);
        CHK_PRT_RET(ret != HCCL_SUCCESS,
            HCCL_ERROR("[Init][Result]errNo[0x%016llx] input rankTable error", HCOM_ERROR_CODE(ret)), ret);
        ret = CfgGetClusterInfo(rankTableM, identify, hcomInfo.params, hcomInfo.rankTable, devType);
        CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[Init][Result]errNo[0x%016llx] cfg get ranktable[%s] info "\
            "error: identify[%s]", HCOM_ERROR_CODE(ret), rankTableM.c_str(), identify.c_str()), ret);
        serverNum = hcomInfo.rankTable.serverNum;
        deviceNumPerServer = (serverNum == 0) ? 0 : (hcomInfo.rankTable.deviceNum + serverNum - 1) / serverNum;

        // 获取multiModuleDiffDeviceNumMode信息
        ret = GetModuleInfo(hcomInfo.rankTable.rankList, multiModuleDiffDeviceNumMode);
        if (ret != HCCL_SUCCESS) {
            HCCL_WARNING("call GetModuleInfo error, failed to get multiModuleDiffDeviceNumMode.");
        }
    } else {
        HcomInfo &hcomInfo = HcomGetCtxHomInfo();
        serverNum = hcomInfo.rankTable.serverNum;
        deviceNumPerServer = (serverNum == 0) ? 0 : (hcomInfo.rankTable.deviceNum + serverNum - 1) / serverNum;
        HCCL_INFO("get HcomInfo from Context");

        // 获取multiModuleDiffDeviceNumMode信息
        ret = GetModuleInfo(hcomInfo.rankTable.rankList, multiModuleDiffDeviceNumMode);
        if (ret != HCCL_SUCCESS) {
            HCCL_WARNING("call GetModuleInfo error, failed to get multiModuleDiffDeviceNumMode.");
        }
    }

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetGroupFromOpDesc(const ge::OpDescPtr &op, std::string &sGroup)
{
    if (ge::AttrUtils::HasAttr(op, "group")) {
        if (ge::AttrUtils::GetStr(op, "group", sGroup) == false) {
            HCCL_ERROR("[GetGroup][OpDesc]errNo[0x%016llx]: get group failed. get \"group\" from opDesc failed", \
                HCOM_ERROR_CODE(HCCL_E_PARA));
            return HCCL_E_PARA;
        }
        CHK_PRT_RET(sGroup.empty(), HCCL_ERROR("[GetGroup][OpDesc]errNo[0x%016llx] get group name failed. group"
            "from opDesc is empty.", HCOM_ERROR_CODE(HCCL_E_PARA)), HCCL_E_PARA);
    } else {
        sGroup = HCCL_WORLD_GROUP;
    }
    HCCL_INFO("get group name[%s] success.", sGroup.c_str());
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetDeviceAndServerNum(const ge::Node &node, s32 &deviceNumPerServer, s32 &serverNum,
    bool &multiModuleDiffDeviceNumMode)
{
    std::string curGroup;
    std::string groupListString;
    CHK_RET(GetGroupFromOpDesc(node.GetOpDesc(), curGroup));
    if (IsOfflineCompilation()) {
        RankTable_t clusterInfo;
        if (curGroup == HCCL_WORLD_GROUP) {
            CHK_RET(GetClusterInfoAndDeviceNum(clusterInfo, deviceNumPerServer));
            serverNum = clusterInfo.serverNum;
            // 获取multiModuleDiffDeviceNumMode信息
            HcclResult ret = GetModuleInfo(clusterInfo.rankList, multiModuleDiffDeviceNumMode);
            if (ret != HCCL_SUCCESS) {
                HCCL_WARNING("call GetModuleInfo error, failed to get multiModuleDiffDeviceNumMode.");
            }
        } else {
            if (ge::GetThreadLocalContext().GetOption(ge::OPTION_EXEC_HCOM_GROUPLIST, groupListString) !=
                ge::GRAPH_SUCCESS) {
                HCCL_ERROR("offline compile need have OPTION_EXEC_HCOM_GROUPLIST.please make true");
                return HCCL_E_PARA;
            }
            CHK_RET(GetDeviceAndServerNumFromGroupList(groupListString, curGroup, serverNum, deviceNumPerServer,
                multiModuleDiffDeviceNumMode));
        }
    } else if (ge::GetThreadLocalContext().GetOption(ge::OPTION_EXEC_HCOM_GROUPLIST, groupListString) ==
        ge::GRAPH_SUCCESS) {
        CHK_RET(GetDeviceAndServerNumFromGroupList(groupListString, curGroup, serverNum, deviceNumPerServer,
            multiModuleDiffDeviceNumMode));
    } else {
        CHK_RET(GetDevAndSerNumFromRankTable(deviceNumPerServer, serverNum, multiModuleDiffDeviceNumMode));
    }
    HCCL_INFO("[GetDeviceAndServerNum] get serverNum[%d] deviceNumPerServer[%d] multiModuleDiffDeviceNumMode[%d].",
        serverNum, deviceNumPerServer, multiModuleDiffDeviceNumMode);

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetBetweenServersStep(s32 serverNum, u32 &commStep)
{
    if ((serverNum & (serverNum - 1)) == 0) {
        // 如果serverNum是2的整数次幂，使用HD算法评估CollectiveOp的taskNum
        commStep += SalLog2(serverNum);
    } else if (serverNum < SERVER_NUM_EIGHT) {
        // 如果serverNum是2的非整数次幂并且小于8,使用ring算法评估CollectiveOp的taskNum
        commStep += (serverNum - 1);
    } else {
        // 计算大于serverNum的最大2的整数次幂的值;以N为rankSize, 使用HD算法评估CollectiveOp的taskNum
        s32 bit = 0;
        while (serverNum > 0) {
            serverNum >>= 1;
            bit++;
        }
        commStep += bit;
    }
    HCCL_DEBUG("Get BetweenServers Step [%u]", commStep);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetIntraComTaskNum(const std::string &sCollectiveType, s32 deviceNumPerServer,
    u64 streamNum, const AlgType &algType, u32 &taskNum, u64 totalSize)
{
    taskNum = 0;
    u32 commStep = 0;
    u32 commStepDeter = 0;

    // 获取通信步骤
    if (algType.algoLevel0 == AlgTypeLevel0::ALG_LEVEL0_8P_RING) {
        commStep += ALG_8P_RING_COMM_STEP;
        commStepDeter = commStep;
    } else if (algType.algoLevel0 == AlgTypeLevel0::ALG_LEVEL0_NP_DOUBLE_RING) {
        commStep += (deviceNumPerServer - 1);
        commStepDeter = commStep;
    } else if (algType.algoLevel0 == AlgTypeLevel0::ALG_LEVEL0_4P_MESH || deviceNumPerServer > TASK_NUM_DEVICE_ONE) {
        // 涉及确定性计算的通信步骤单独计算
        if (totalSize <= HCCL_SMALL_COUNT_GRAPH_64_KB) {
            commStepDeter += (deviceNumPerServer - 1);
        } else {
            commStepDeter += (GetExternalInputHcclDeterministic() ?
                ((deviceNumPerServer - 1) * (deviceNumPerServer - 1)) : (deviceNumPerServer - 1));
        }
        commStep += (deviceNumPerServer - 1);
    }
    // 计算通信task的数量
    if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLREDUCE) {
        taskNum = REDUCESCATTER_DEFAULT_COM_STEP * commStepDeter + ALLGATHER_DEFAULT_COM_STEP * commStep;
    } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLGATHER) {
        taskNum = ALLGATHER_DEFAULT_COM_STEP * commStep;
    } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_REDUCESCATTER) {
        taskNum = REDUCESCATTER_DEFAULT_COM_STEP * commStepDeter;
    } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALL ||
               sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALLV ||
               sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALLVC) {
        commStep = deviceNumPerServer - 1; // 按照pairwise计算server内通信步数
        taskNum = ALLTOALL_DEFAULT_COM_STEP * commStep;
    } else {
        HCCL_ERROR("The current operator is not supported tasknum accurate evaluation.");
        return HCCL_E_NOT_SUPPORT;
    }
    HCCL_INFO("[GetIntraComTaskNum] op[%s], cur tasknum is[%u], commStep[%u], totalSize[%llu]",
        sCollectiveType.c_str(), taskNum, commStep, totalSize);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetInterComTaskNum(const std::string &sCollectiveType, s32 serverNum, s32 deviceNumPerServer,
    DevType devType, u32 &taskNum)
{
    taskNum = 0;
    u32 commStep = 0;

    // 获取server间通信步骤
    if (serverNum > SERVER_NUM_ONE) {
        CHK_RET(GetBetweenServersStep(serverNum, commStep)); // 默认情况下根据serverNum按ring或HD算法评估
        // 计算通信task的数量
        if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLREDUCE) {
            taskNum = ALLREDUCE_DEFAULT_COM_STEP * commStep;
        } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLGATHER) {
            taskNum = ALLGATHER_DEFAULT_COM_STEP * commStep;
        } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_REDUCESCATTER) {
            taskNum = REDUCESCATTER_DEFAULT_COM_STEP * commStep;
        } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALL ||
                   sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALLV ||
                   sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALLVC) {
            bool useOneLevelAlgorithm = (GetExternalInputHcclAlgoConfig()[0] == HcclAlgoType::HCCL_ALGO_TYPE_NA &&
                GetExternalInputHcclAlgoConfig()[1] == HcclAlgoType::HCCL_ALGO_TYPE_PAIRWISE);
            s32 meshNum = (devType == DevType::DEV_TYPE_910) ? serverNum * 2 : serverNum;
            commStep = useOneLevelAlgorithm ? ((meshNum - 1) * deviceNumPerServer) : (meshNum - 1);
            taskNum = ALLTOALL_DEFAULT_COM_STEP * commStep;
        } else {
            HCCL_ERROR("The current operator is not supported tasknum accurate evaluation.");
            return HCCL_E_NOT_SUPPORT;
        }
    }
    HCCL_INFO("[GetInterComTaskNum]op[%s], cur tasknum is[%u], commStep[%u].",
        sCollectiveType.c_str(), taskNum, commStep);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetCombineComTaskNum(const std::string &sCollectiveType, s32 serverNum, s32 deviceNumPerServer,
    u32 &intraTaskNum, u32 &interTaskNum)
{
    // 打平拓扑server内通信task数量为0
    intraTaskNum = 0;

    interTaskNum = 0;
    u32 commStep = deviceNumPerServer * serverNum - 1; // 默认根据ring算法评估

    // 计算通信task的数量
    if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLREDUCE) {
        interTaskNum = ALLREDUCE_DEFAULT_COM_STEP * commStep;
    } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLGATHER) {
        interTaskNum = ALLGATHER_DEFAULT_COM_STEP * commStep;
    } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_REDUCESCATTER) {
        interTaskNum = REDUCESCATTER_DEFAULT_COM_STEP * commStep;
    } else if (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALL ||
                sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALLV ||
                sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLTOALLVC) {
        interTaskNum = ALLTOALL_DEFAULT_COM_STEP * commStep;
    } else {
        HCCL_ERROR("[HcomOpUtils][GetCombineComTaskNum]The current operator [%s] do not support tasknum "
            "accurate evaluation.", sCollectiveType.c_str());
        return HCCL_E_NOT_SUPPORT;
    }

    HCCL_INFO("[HcomOpUtils][GetCombineComTaskNum]op[%s], cur intraTaskNum is[%u], interTaskNum is[%u], commStep[%u].",
        sCollectiveType.c_str(), intraTaskNum, interTaskNum, commStep);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetTensorNum(const ge::Node &node, const std::string &sCollectiveType, u32 &tensorNum)
{
    constexpr const char *kCleanSeparately = "1";
    std::string atomic_clean_policy;
    bool needCleanSeparately = (ge::GetThreadLocalContext().GetOption(ge::ATOMIC_CLEAN_POLICY, atomic_clean_policy)\
        == ge::GRAPH_SUCCESS) && (atomic_clean_policy == kCleanSeparately);
    if (needCleanSeparately && ((sCollectiveType == HCCL_KERNEL_OP_TYPE_REDUCESCATTER) ||\
        (sCollectiveType == HCCL_KERNEL_OP_TYPE_ALLREDUCE) || (sCollectiveType == HCCL_KERNEL_OP_TYPE_REDUCE))) {
        // 获取Tensor的个数
        tensorNum = node.GetOpDesc()->GetInputsSize();
    } else {
        tensorNum = 0;
    }
    HCCL_DEBUG("[GetTensorNum] sCollectiveType[%s] tensorNum[%u].", sCollectiveType.c_str(), tensorNum);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetTensorSize(const ge::GeTensorDesc &tensorDesc, int64_t &size)
{
    auto shape = tensorDesc.GetShape();
    auto geDataType = tensorDesc.GetDataType();
    auto format = tensorDesc.GetFormat();

    int64_t sizeTemp = 0;
    bool bErr = (ge::TensorUtils::CalcTensorMemSize(shape, format, geDataType, sizeTemp) != ge::GRAPH_SUCCESS);
    CHK_PRT_RET((bErr) || (sizeTemp < 0), HCCL_ERROR("[Get][TensorMemSize]In GetTensorMemSize, CalcTensorMemSize"
        "failed, Format[%d], dataType[%d], size[%lld]", format, geDataType, sizeTemp), HCCL_E_PARA);

    size = sizeTemp;
    HCCL_DEBUG("[HcomOpsKernelBuilder][GetTensorSize]tensorSize %lld", size);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAllTensorSize(const ge::OpDescPtr &op,
    u32 tensorNum, std::vector<int64_t> &tensorSize)
{
    for (size_t i = 0; i < tensorNum; i++) {
        auto inTensor = op->GetInputDesc(i);
        int64_t size = 0;
        HcclResult ret = GetTensorSize(inTensor, size);
        CHK_PRT_RET(ret, HCCL_ERROR("[Get][AllTensorSize]node[%s] input[%u] GetTensorSize failed.",
            op->GetName().c_str(), i), ret);
        HCCL_DEBUG("[HcomOpsKernelBuilder] node[%s] has %u inputs, input[%u] size %lld bytes.", op->GetName().c_str(),
            op->GetInputsSize(), i, size);
        tensorSize.push_back(size);
    }

    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetTaskNumFromCrackSize(const ge::Node &node, u32 tensorNum, u32 &taskNum)
{
    bool crackSizeBigger32 = false;
    s64 tensorSize[tensorNum] = {0};
    s64 crackSize[tensorNum] = {0};
    std::vector<int64_t> tensorSizeTemp;

    auto op = node.GetOpDesc();
    CHK_PTR_NULL(op);
    // 获取tensor的大小
    CHK_RET(GetAllTensorSize(op, tensorNum, tensorSizeTemp));
    CHK_SAFETY_FUNC_RET(memcpy_s(tensorSize, tensorNum * sizeof(s64), tensorSizeTemp.data(),
        tensorSizeTemp.size() * sizeof(s64)));
    // 获取缝隙的大小
    for (u32 i = 0; i < tensorNum; i++) {
        s64 crackSizeTemp = 0;
        crackSizeTemp = (tensorSize[i] + TENSOR_ALIGNMENT_32 - 1) / TENSOR_ALIGNMENT_32 * TENSOR_ALIGNMENT_32\
            + TENSOR_ALIGNMENT_32;
        crackSizeTemp = (crackSizeTemp + TENSOR_ALIGNMENT_512 - 1) / TENSOR_ALIGNMENT_512 * TENSOR_ALIGNMENT_512;
        crackSizeTemp = crackSizeTemp - tensorSize[i];
        crackSize[i] = crackSizeTemp;
        if (crackSize[i] < AICORE_MIN_CLEAR_ZEOR_SIZE) {
            taskNum++;
        } else if (!crackSizeBigger32) {
            crackSizeBigger32 = true;
        }
    }
    if (crackSizeBigger32) {
        taskNum++;
    }
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetTensorCleanTaskNum(const ge::Node &node,
    const std::string &sCollectiveType, u32 &taskNum)
{
    u32 tensorNum = 0;
    // 获取tensor的数量
    CHK_RET(GetTensorNum(node, sCollectiveType, tensorNum));
    if (tensorNum != 0) {
        CHK_RET(GetTaskNumFromCrackSize(node, tensorNum, taskNum));
    }
    HCCL_DEBUG("[GetTensorCleanTaskNum] cur task num[%u].", taskNum);
    return HCCL_SUCCESS;
}

HcclResult HcomOpUtils::GetAllReduceScratchMemSize(const string &sGroup, const ge::Node& node,
    s32 serverNum, s32 rankSize, const u64 count, const HcclDataType dataType, u64 &getMemSize)
{
    u64 scratchSize = 0;
    std::string groupListString;
    s32 backloggedGroupSize = 0;
    std::vector<u32> groupRanks;
    bool no_impl_compile = IsOfflineCompilation() ||
        (ge::GetThreadLocalContext().GetOption(ge::OPTION_EXEC_HCOM_GROUPLIST, groupListString) == ge::GRAPH_SUCCESS) ||
        ((!ge::AttrUtils::HasAttr(node.GetOpDesc(), "comm"))&&
        ((HcomGetbackloggedByGroup(sGroup.c_str(), groupRanks, backloggedGroupSize) == HCCL_SUCCESS) &&
        (backloggedGroupSize != 0)));
    if (no_impl_compile) {
        HcclResult ret = GetAllReduceScratchSizeWithoutDev(sGroup, node, serverNum, rankSize, count, dataType,
            scratchSize);
        CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("no_impl_compile getallreducescratchmemsize fail ",
            HCOM_ERROR_CODE(HCCL_E_PARA)), HCCL_E_PARA);
    } else if (ge::AttrUtils::HasAttr(node.GetOpDesc(), "comm")) {
        int64_t hcomComm = 0;
        bool bRet = ge::AttrUtils::GetInt(node.GetOpDesc(), "comm", hcomComm);
        CHK_PRT_RET(!bRet, HCCL_ERROR("errNo[0x%016llx] get attr \"comm\" failed. ", HCOM_ERROR_CODE(HCCL_E_PARA)),\
            HCCL_E_PARA);
        if (hcomComm != static_cast<int64_t>(CommNumHcom::COMM_VALUE_DEFAULT)) {
            CHK_RET(HcclCommGraphGetAllReduceScratchSize(hcomComm, count, dataType, scratchSize));
            HCCL_INFO("[HcomCalcOpRunningParam][GetComm][%d].", hcomComm);
        } else {
            CHK_RET(HcomGetAllReduceScratchSize(sGroup.c_str(), count, dataType, scratchSize));
        }
    } else {
        CHK_RET(HcomGetAllReduceScratchSize(sGroup.c_str(), count, dataType, scratchSize));
    }
    u64 memSize = SIZE_TABLE[dataType] * count;

    HCCL_DEBUG("[GetAllReduceScratchMemSize] serverNum=%u, memSize=%llu, rankSize=%u, scratchSize=%llu",
               serverNum, memSize, rankSize, scratchSize);
    getMemSize += scratchSize;

    return HCCL_SUCCESS;
}
}
